轨迹记录 Sample详情

最后更新时间:2020年12月15日

功能介绍

随着定位、跟踪、存储技术的快速发展,位置采集和移动计算技术的进步,已经产生了大量的空间轨迹数据。通过搜集大量的人、动物和车辆等移动轨迹数据,进而了解人的生活规律,动物的活动习性,以及一个城市的交通状况等。

轨迹记录就是在时空环境下,记录一个或多个移动对象在运动过程中的空间位置信息和属性信息的变化。这些信息根据时间的先后顺序构成了轨迹。多用于交通、气象、生态和移动服务等领域,理解和分析这些轨迹记录可以帮助我们很好挖掘信息,解决许多重要的问题。例如,对于大众来说,他们希望可以记录生活,同时分享给他人,通过轨迹记录功能可以记录实时位置信息,并可在未来的某一时间段进行回放,为他人提供参考。目前,该功能已应用于常用的地图导航软件,如百度地图,以及运动软件、旅游软件等和地理信息有关的软件中;对于出租车司机来说,他们希望快速找到搭载的乘客以获取盈利,通过轨迹记录可以分析并预测一个区域未来的乘客数量,可为出租车司机提供最快找到乘客的路线;对于台风预警人员,可以通过对各种数据的监测以及台风历史线路的轨迹回放,据制定相应的应对方案。由此可见,轨迹记录正在被越来越多的行业和用户所需要。

MapGIS Mobile SDK提供了轨迹记录功能模块,调用其接口可快速将轨迹记录功能集成于各种场景应用中。

功能接口

轨迹记录功能对应的API程序包为com.zondy.mapgis.track(10.3版本:com.zondy.mapgis.android.track),核心类为轨迹类Track,核心接口如下所示:

接口 说明
addLocation() 添加定位信息(添加的定位信息单位必须是经纬度)
setTrackFeatureCls() 设置简单要素类(轨迹存放到点简单要素类中)
setSmooth() 设置是否平滑处理
setTimeInterval() 设置GPS数据时间间隔(默认时间间隔1秒)
setMindistanceInterval() 设置最小距离间隔(单位为米,默认的距离间隔是5米)
setMatchLineLayer() 设置道路匹配线矢量图层
startTrack() 开始轨迹记录
setTrackerListener() 设置轨迹监听
endTrack() 结束轨迹记录

示例数据说明:

(1)轨迹记录的数据存放的数据库:/MapGISSample/Track/TrackSample.hdb

(2)轨迹记录道路匹配的数据库:/MapGISSample/Track/TrackMatch.hdb

(3)轨迹数据(gpx格式文件):/MapGISSample/Track/TrackData.gpx

轨迹自采集

轨迹自动采集功能,可以将移动定位结果自动保存为离线矢量数据,可实现轨迹点去重、剔除异常点、轨迹平滑、自动加密和稀疏的处理,也可利用轨迹与线要素的自动匹配功能实现抓路功能。轨迹自动采集功能,主要为结合实时定位功能,根据设置的轨迹采集规则与模式(如按时间间隔采集),采集并存储当前定位点信息。

轨迹自采集功能通过轨迹记录类(Track)实现,通过实现流程如下图所示:

轨迹自采集功能实现流程.png

1

构造轨迹记录对象

构造轨迹记录对象(Track),并设置轨迹记录模式。SDK提供了多种辅助轨迹采集的功能,例如能够对定位点进行去重、剔除异常点,对轨迹进行平滑、自动加密和稀疏处理,还有轨迹与线要素的自动匹配功能,可根据需要进行相应的代码设置。

    //构造轨迹记录对象
    Track mTrack = new Track();
    //设置是否平滑处理轨迹线
    mTrack.setSmooth(true);
    //设置最小距离间隔:单位为米,默认的距离间隔是5米,用于定义轨迹点采集的距离间隔,可实现自动加密和稀疏
    mTrack.setMindistanceInterval(50);
    //设置GPS数据时间间隔:默认时间间隔1秒
    mTrack.setTimeInterval(5); 

    //设置是否用户自定义定位点
    mTrack.setCostomLocation(true);
    //设置最小距离间隔(单位为米,默认的距离间隔是5米)
    mTrack.setDistanceInterval(5);

    //方式一:通过已加载的地图文档中道路线匹配
    //设置轨迹与道路匹配:设置成功后,采集轨迹点将根据道路线自动进行纠偏、匹配处理
    int index=mapView.getMap().indexOf("道路线");//获取矢量图层
    vectorLayer= (VectorLayer) mapView.getMap().getLayer(index);
    mTrack.setMatchLineLayer(vectorLayer);//设置道路匹配线矢量图层

    //方式二:通过矢量数据库hdb中的道路线匹配
    //创建数据库对象,道路线数据库,供道路匹配用
    String strGDBPath = Environment.getExternalStorageDirectory().getPath()+ "/MapGISSample/Track/TrackMatch.hdb";
    DataBase dataBase = DataBaseUtils.OpenDataBase(strGDBPath);
    if (dataBase != null && dataBase.hasOpened())
    {
        //获取所有简单要素类的id
        int[] intList = dataBase.getXclses(XClsType.XSFCls, 0);
        for (int i = 0; i < intList.length; i++)
        {
            //获取名称为“道路线”的要素类
            if (dataBase.getXclsName(XClsType.XSFCls, intList[i]).equals("道路线"))
            {
                //创建要素类
                SFeatureCls sFeatureCls = new SFeatureCls(dataBase);
                //要素类打开
                long sfclsOP = sFeatureCls.open(intList[i], 0);
                if (sfclsOP > 0)
                {
                    //创建矢量图层
                    VectorLayer vectorLayer = new VectorLayer(VectorLayerType.SFclsLayer);
                    vectorLayer.setURL(sFeatureCls.getURL());
                    vectorLayer.setName(sFeatureCls.getName());
                    //叠加图层
                    mapView.getMap().append(vectorLayer);
                    mapView.forceRefresh();
                    //设置道路匹配线矢量图层
                    mTrack.setMatchLineLayer(vectorLayer);
                    sFeatureCls.close();
                }
            }
        }
        //关闭数据库
        dataBase.close();
    }

2

设置简单要素类

轨迹记录采集的结果是作为矢量数据保存到移动地理数据库中,所以在开始记录之前需要为其设置保存的简单要素类。

    //保存轨迹数据的离线矢量数据库
    String strGDBPath = Environment.getExternalStorageDirectory().getPath()+"/MapGISSample/Track/TrackSample.hdb";
    //打开数据库
    DataBase dataBase = DataBaseUtils.OpenDataBase(strGDBPath);
    if (dataBase != null && dataBase.hasOpened())
    {
        //字段集
        Fields fieldCreate = new Fields();
        //字段,可传递轨迹的一些信息,如人名,时间,长度等
        Field nameField = new Field();
        nameField.setFieldType(FieldType.fldStr);
        nameField.setFieldLength((short) 30);
        nameField.setFieldName("轨迹采集者");

        //追加字段
        int addFild = fieldCreate.appendField(nameField);

        int[] intList = dataBase.getXclses(XClsType.XSFCls, 0);
        for (int i = 0; i < intList.length; i++) {
            String xClsName = dataBase.getXclsName(XClsType.XSFCls, intList[i]);
            if (mTrackClsName.equals(xClsName)) {
                return;
            }
        }
        //创建简单要素类
        SFeatureCls sFeatureCls = new SFeatureCls(dataBase);
        int id = sFeatureCls.create(mTrackClsName, GeomType.GeomLin, 0, 1, fieldCreate);
        //关闭简单要素类与数据库
        sFeatureCls.close();
        dataBase.close();
    }

3

记录轨迹

记录轨迹,通过轨迹记录对象(Track类对象),调用startTrack()开启轨迹记录。

//开始记录轨迹
mTrack.startTrack();

同时需要不断地为轨迹记录对象添加定位信息,一般采用实时定位方式,在定位监听回调中获取位置信息,调用addLocation()添加定位信息。可采用Android原生GPS定位方式获取位置信息,关键代码如下所示,也可通过其他方式获取。

//使用指定的提供者注册位置更新
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 1, locationListener);
//用于在位置更改时从LocationManager接收通知
private LocationListener locationListener = new LocationListener() {
    @Override
    public void onLocationChanged(Location location) {
        //构造定位信息类,设置经度、纬度
        GNNSInfo gnnsInfo = new GNNSInfo();
        gnnsInfo.setlongitude(location.getLongitude());
        gnnsInfo.setlatitude(location.getLatitude());
        //添加定位信息(添加的定位信息单位必须是经纬度)
        mTrack.addLocation(gnnsInfo);
    }
};

如果需要停止轨迹记录,可调用endTrack()实现。

4

轨迹监听

为轨迹记录对象设置轨迹监听器,动态获取轨迹点。

    //设置轨迹监听
    mTrack.setTrackerListener(new Track.TrackListener() {

		@Override
		public void onLocationAdjusted(final List gnnsInfoList) {
			if(gnnsInfoList == null || gnnsInfoList.size() <= 0){
	          return;
	        }

	        //停止服务请求再添加graphic点,绘制,避免在对graphic编辑的时候进行刷新
	        mapView.stopCurRequest(new MapView.MapViewStopCurRequestCallback() {

	            @Override
	            public void onDidStopCurRequest() {
	               // TODO Auto-generated method stub
	               //绘制模拟运动图标
	               if (simuDotGraphicImage == null) {
	                    simuDotGraphicImage = new GraphicImage();
	                    simuDotGraphicImage.setImage(simuBitmap);
	                    simuDotGraphicImage.setAnchorPoint(new PointF((float) 0.5, (float) 0.5));
	                    simuDotImageOverlay.addGraphic(simuDotGraphicImage);
	                }

	                //轨迹模拟得到的点绘制而成的线
	                if (simuTrackLine == null) {
	                   simuTrackLine = new GraphicPolylin();
	                   simuTrackLine.setColor(Color.RED);
	                   simuTrackLine.setLineWidth(3);
	                   simuTrackPolylinOverlay.addGraphic(simuTrackLine);
	                }
	                for (int i = 0;i < gnnsInfoList.size();i++){
	                    GNNSInfo gnnsinfo = gnnsInfoList.get(i);
	                    Log.e("轨迹点坐标", "X:" + gnnsinfo.getlongitude() + "\nY:" + gnnsinfo.getlatitude());

	                    //构造Dot点
	                    Dot dot = new Dot(gnnsinfo.getlongitude(), gnnsinfo.getlatitude());
	                   //经纬度转墨卡托,便于显示在地图上
	                   SpaProjection.lonLat2Mercator(dot);
	                   //根据路径点修改模拟运动图片的位置
	                    simuDotGraphicImage.setPoint(dot);
	                    //为模拟的轨迹添加点
	                    simuTrackLine.appendPoint(dot);
	                }
	                mapView.refresh();
	            }
	        });		
           }
    });

5

存储轨迹点数据

轨迹记录采集的结果是作为矢量数据保存到之前设置的离线地理数据库的简单要素类中。

        DataBase dataBase = null;
        //打开轨迹记录的数据存放的数据库
        dataBase = DataBaseUtils.OpenDataBase(=Environment.getExternalStorageDirectory().getPath()+"/MapGISSample/Track/TrackSample.hdb");
        if(dataBase != null && dataBase.hasOpened()){
            //打开简单要素类对象-轨迹记录数据存储类
            SFeatureCls sFeatureCls = new SFeatureCls(dataBase);
            long sOpen = sFeatureCls.open(mTrackClsName, 0);
            if(sOpen > 0){
                HashMap attributeMap = new HashMap<>();
                attributeMap.put("轨迹采集者", null);
                //轨迹线
                Geometry geometry = Graphic.toGeometry(simuTrackLine);
                LinInfo linInfo = new LinInfo();
                linInfo.setLibID((short) 0);
                linInfo.setLinStyID(1);
                linInfo.setOutClr1(6);
                linInfo.setOutPenW1(5);
                //要素对象
                Feature feature = new Feature(attributeMap, geometry, linInfo);
                //将轨迹线要素存储到简单要素类
                FeatureEdit featureEdit = new FeatureEdit(sFeatureCls);
                long append = featureEdit.append(feature);
                Log.e("AppendFeature", append + "");
                //关闭简单要素类
                sFeatureCls.close();
            }
            //关闭数据库
            dataBase.close();
        }

轨迹记录实现效果如下所示:

轨迹记录.jpg

轨迹回放

轨迹自动采集功能,会将定位结果自动保存为移动端的离线矢量数据,一条轨迹对应一个地图要素,要素类型为多点几何对象。也可以将轨迹数据保存至业务关系数据库,以及kml、gpx等格式文件中,或者将离线轨迹矢量数据同步上传到GIS服务器等等,具体可根据业务需求进行选择。采集轨迹数据后,当需要查看已经记录的轨迹路线情况,则需要用到轨迹回放。轨迹回放功能的实现原理,即先读取采集的轨迹点数据,基于点的标绘功能,动态模拟目标点在地图上的运动轨迹。

1

获取轨迹点

从hdb地理数据库中获取轨迹采集时记录的轨迹点。

    String mgdbPath = Environment.getExternalStorageDirectory().getPath()+"/MapGISSample/Track/TrackSample.hdb";

    //打开数据库
    DataBase dataBase = DataBaseUtils.OpenDataBase(mgdbPath);

    if (dataBase != null && dataBase.hasOpened()) {
       //获取所有简单要素类的id
       int[] intList = dataBase.getXclses(XClsType.XSFCls, 0);
       for (int i = 0; i < intList.length; i++){
          //获取名称为“模拟轨迹”的要素类
          if (dataBase.getXclsName(XClsType.XSFCls, intList[i]).equals(mTrackClsName)) {
              //创建要素类
              SFeatureCls sFeatureCls = new SFeatureCls(dataBase);
              //打开要素类
              long sfclsOP = sFeatureCls.open(mTrackClsName, 0);
              if (sfclsOP > 0) {
                 //通过查询获取轨迹线要素
                 FeatureQuery featureQuery = new FeatureQuery(sFeatureCls);
                 if (featureQuery != null) {
                    QueryDef queryDef = new QueryDef();
                    queryDef.setFilter(null);
                    queryDef.setWithSpatial(true);
                    queryDef.setPagination(1, 10);
                    featureQuery.setQueryDef(queryDef);
                    FeaturePagedResult featurePagedResult = featureQuery.query();
                    if (featurePagedResult != null && featurePagedResult.getPageCount() > 0) {
                       Feature finalFeature = null;
                       //解析查询结果
                       for (int f = 1; f <= featurePagedResult.getPageCount(); f++) {
                            List featureList = featurePagedResult.getPage(f);
                            if (featureList != null && featureList.size() > 0) {
                                finalFeature = featureList.get(featureList.size() - 1);
                            }
                       }

                       //获取最后一个几何对象,即最后一次模拟轨迹记录产生的几何对象
                       if(finalFeature == null){
                            return;
                       }
                       //获取最后一个几何对象的几何信息
                       Geometry geometry = finalFeature.getGeometry();
                       //获取几何类型
                       GeometryType geometryType1 = geometry.getType();
                       //判断几何对象类型(一条轨迹存储在一个简单要素类中,并且以一个要素存在,几何对象为多点)
                       if (geometryType1 == GeometryType.GeoVarLine) {
                          //转换为多点
                          GeoVarLine geoVarLine = (GeoVarLine) geometry;
                          //获取每一个点
                          for (int j = 0; j < geoVarLine.getDotNum(); j++){
                              Dot dot = geoVarLine.get2D(j);
                              mgdbDots.add(dot);
                          }
                       }
                    }
                 }
                 //关闭简单要素类
                 sFeatureCls.close();
              }
           }
        }
        //绘制hdb中的轨迹点(即下面绘制代码)
        //关闭数据库
        dataBase.close();
    }

2

轨迹绘制

获取轨迹点之后,可以利用多点图形对象进行绘制。

    //构建多点图形对象,并设置颜色、点大小、点集,然后添加到覆盖物图层进行绘制
    if (mgdbDots.size() > 0) {
         if (trackMultiPoint == null) {
            trackMultiPoint = new GraphicMultiPoint();
            trackMultiPoint.setColor(Color.GREEN);
            trackMultiPoint.setPointSize(5);
            trackMultiPointOverlay.addGraphic(trackMultiPoint);
         }
         trackMultiPoint.setPoints(mgdbDots);
         mapView.refresh();
    }